<?php
namespace app\websocket;

use Workerman\Connection\TcpConnection;

use Webman\Openai\Chat;
use Workerman\Protocols\Http\Chunk;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use Workerman\Worker;
use Workerman\Timer;

use support\Log;
use think\facade\Db;
use support\Redis;


class ChatHandler
{

    private $redis_config;
    private $defaultUserId = 'testuser';
    private $tyxcUrl = 'https://nlp.aliyuncs.com/v2/api/chat/send';
    private $check_time_out = 3;


    public function onWorkerStart (Worker $worker)
    {
      $this->redis_config = Redis::connection("config");
    }

    public function onWebSocketConnect(TcpConnection $connection, $http_buffer)
    {

      $connection->Authentication = false;
      //创建定时器，如果连接超过10秒未认证，则关闭连接
      Timer::add($this->check_time_out, function() use ($connection){
        if($connection->Authentication == false)
        {
          $connection->send(json_encode(['status'=>400,'message'=>'Authentication failed']));
          $connection->close();
        }
      }, [], false);
    }


    public function onMessage(TcpConnection $connection, $data)
    {

      Log::info("onMessage:".$data. "\n");
      $dataJson = json_decode($data,true);

      if($dataJson == null)
      {
        $connection->send(json_encode(['status'=>400,'message'=>'data format error']));
        return;
      }

      // 根据类型不同，执行不同操作接口
      if(isset($dataJson['meta_type']))
      {
        // 验证信息
        $meta_id = $dataJson['meta_id'];
        $meta_type = $dataJson['meta_type'];
        $chat_type = $dataJson['chat_type'];
        //判断参数是否存在
        if(!isset($meta_id) || !isset($meta_type) || !isset($chat_type))
        {
          $connection->send(json_encode(['status'=>400,'message'=>'meta type not found']));
          return;
        }

        $this->checkUser($connection,$meta_id,$meta_type,$chat_type);

      }else if(isset($dataJson['messages']))
      {
        if($connection->Authentication != true)
        {
          $connection->send(json_encode(['status'=>400,'message'=>'Authentication failed']));
          return;
        }
  
        switch($connection->type)
        {
          case 'tyxc':
            $this->tyxc($connection,$dataJson);
            break;
          case 'paddspeech':
            $connection->send(json_encode(['status'=>400,'message'=>'paddspeech not server']));
            break;
          default:
            $connection->send(json_encode(['status'=>400,'message'=>'type not found']));
            break;
        }
      }
      else{
        $connection->send(json_encode(['status'=>'400','message'=>'messages not found']));
      }

    }


    public function onClose(TcpConnection $connection)
    {
        $connection->send(json_encode(['status'=>400,'message'=>'connection closed']));
    }


    private function checkUser(TcpConnection &$connection,$meta_id,$meta_type,$chat_type)
    {
      switch ($meta_type) {
        case 'web':
          $res = Db::name("meta_web")
              ->field('meta_id, role_id')
              ->where('meta_id', $meta_id)
              ->find();
          if($res == null)
          {
            $connection->send(json_encode(['status'=>400,'message'=>'meta not found']));
            $connection->close();
          }
          $connection->type = $chat_type;
          $connection->Authentication = true;
          $connection->role_id = $res['role_id'];
          $connection->send(json_encode(['status'=>200,'name'=>'connected','message'=>"coneected to chat server"]));
          break;
        case 'ue':
          $res = Db::name("ue")
                ->field('meta_id, role_id')
                ->where('meta_id', $meta_id)
                ->find();
          if($res == null)
          {
            $connection->send(json_encode(['status'=>400,'message'=>'meta not found']));
            $connection->close();
          }
          $connection->type = $chat_type;
          $connection->Authentication = true;
          $connection->role_id = $res['role_id'];
          $connection->send(json_encode(['status'=>200,'name'=>'connected','message'=>"coneected to chat server"]));
          break;
        default:
          $connection->send(json_encode(['status'=>400,'message'=>'meta type not found']));
          $connection->close();
          break;
      }
    }

    private function tyxc($connection,$data)
    {
      $chat_config = $this->redis_config->get("chat_config");
      $chat_config = json_decode($chat_config,true);

      if(!isset($chat_config["tyxc"]) )
      {
        $connection->send(json_encode(['status'=>400,'message'=>"chat 未配置"]));
      }

    
      $userId = isset($data['userId'])? $data['userId'] : $this->defaultUserId;
      $userMessages = $data['messages'];
      $apiKey = $chat_config["tyxc"]["appkey"];
      
      $headers = chatCreateHeader($apiKey);
      $body = chatCreateBody($connection->role_id,$userId,$userMessages);

      $http = new Chat(['api' => $this->tyxcUrl]);
      $options = [
          "headers" => $headers,
          "stream" => function($parsedData) use ($connection) {
            if(isset( $parsedData["choices"]) && count($parsedData["choices"]) > 0)
              {
                  $messages = $parsedData["choices"][0]["messages"];
                  if(count($messages) > 0)
                  {
                      $message = $messages[0];
                      if(!empty($message["content"] ) )
                      {
                        $connection->send(json_encode([
                            'status' => 200,
                            'name' => 'message',
                            'message' => 'message create ing',
                            'content'=>$message["content"],
                        ]));
                      }
                      if($message["finishReason"] == "stop")
                      {
                        Log::info("stream----:".json_encode($message, JSON_UNESCAPED_UNICODE). "\n");
                        $connection->send(json_encode([
                            'status' => 200,
                            'message'=>'message create completed',
                            "name" => "completed",
                            "chatname" => $message["name"],
                            "role" => $message["role"]
                        ]));
                        $connection->close();
                      }
                  }
              };
          },
          'complete' => function($result, $response) use ($connection) {
            Log::info("complete:".json_encode($result, JSON_UNESCAPED_UNICODE). "\n");
            if (isset($result['error'])) {
                $connection->send(json_encode([
                    'status' => 400,
                    'message'=>json_encode($result, JSON_UNESCAPED_UNICODE)
                ]));
            }else{
                $connection->send(json_encode([
                    'status' => 200,
                    'message'=>'message create completed',
                    "name" => "completed",
                ]));
            }
            $connection->close();
          }
      ];

      $http->completions($body,$options);
    }


}


?>